package search;

import interfaces.SearchDataBase;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Set;

import search.items.SearchDB;
import domain.items.Post;

public class SearchDBManager extends SearchDB implements SearchDataBase {


	/**
	 * Constructor
	 */
	public SearchDBManager() {
		super();
	}


	/**
	 * adds the PostID to the map which maps Users to their posts
	 * the info about the user who's post it is, is retrieved from post itself.
	 * @param post
	 */
	private void addUserPost(Post post) {
		String tUserName = post.getOwner();

		Set<Long> tPostsList = this._usersToPostsIndex.get(tUserName);
		if (tPostsList == null) {
			tPostsList = new HashSet<Long>();
			this._usersToPostsIndex.put(tUserName, tPostsList);
		}
		tPostsList.add(post.getId());
	}


	/**
	 * adds the PostID to the map which maps Dates to posts from that Date.
	 * the info about the Date the post was written, is retrieved from post itself.
	 * @param post
	 */
	private void addDatePost(Post post) {
		//		Calendar tPostDate = this.parseDate(post.getDate());
		Calendar tPostDate = null; // ayal
		Set<Long> tPostsList = this._datesToPostsIndex.get(tPostDate);
		if (tPostsList == null) {
			tPostsList = new HashSet<Long>();
			this._datesToPostsIndex.put(tPostDate, tPostsList);
		}
		tPostsList.add(post.getId());
	}


	/**
	 * @param date
	 * @return a Calendar (date) equals to 'date' only by fields of Year, Month, Day
	 */
	private Calendar parseDate(Calendar date) {
		int tYear = date.get(Calendar.YEAR);
		int tMonth = date.get(Calendar.MONTH);
		int tDay = date.get(Calendar.DAY_OF_MONTH);
		return new GregorianCalendar(tYear, tMonth, tDay);
	}

	
	/**
	 * adds the Post and its ID to all the maps where it is needed
	 * @PreCondition - post.getID() is unique for each different post
	 * @param post
	 * @return the post's ID
	 */
	private Long addPost(Post post) {
		Long tPostID = post.getId();	//gets the ID of the post
		if (!this._postsIndex.containsKey(tPostID)) {	//if post is new, and its the first time we encounter it
			//we need to add it to all the maps
			this._postsIndex.put(tPostID, post);
			this.addDatePost(post);
			this.addUserPost(post);
		}
		return tPostID;
	}



	/* (non-Javadoc)
	 * @see interfaces.SearchDataBase#addWordReference(java.lang.String, domain.items.Post)
	 */
	public void addWordReference(String word, Post post) {
		System.out.println("I'm Adding a word ref");
		//first we find the ID matching word
		Long tWordID = this._wordsIndex.get(word);	//gets the ID matching word
		if (tWordID == null) {	//if word is new, and its the first time we encounter it
			long tNewID = this._wordsIndex.size() + 1;	//give it a new ID. the ID is a running number, from 1..._wordsIndex.size()
			tWordID = tNewID;
			this._wordsIndex.put(word, tWordID);	//add the new Word and its ID to the Map
			//now we need to create a new (empty) List of postID, which will hold all the ID's of posts that contains this word
			this._wordsToPostsIndex.put(tWordID, new HashSet<Long>());
		}

		//then we find the ID matching post
		Long tPostID = this.addPost(post);

		//now we have WordID & PostID, and we update the map
		Set<Long> tMatchingPosts = this._wordsToPostsIndex.get(tWordID);	//get all postID's of Posts that contains word
		if (!tMatchingPosts.contains(tPostID))	{	//if the reference doesn't exist already
			tMatchingPosts.add(tPostID);	//then we add the new reference
		}
	}


	public Set<Post> getWordReference(String word) {
		System.out.println("I'm getting a word ref");
		Long tWordID = this._wordsIndex.get(word);	//gets the ID matching word
		if (tWordID == null)	//if the word doesn't exist in the forum
			return new HashSet<Post>();	//return an empty list

		Set<Long> tPostsID = this._wordsToPostsIndex.get(tWordID);

		return this.getPostsFromIDs(tPostsID);
	}

	/**
	 * gets a list of postID's, and extract all the matching posts from this._postsIndex
	 * @param postsIDs - a list of PostID's
	 * @return a list of Posts matching the PostID's
	 */
	private Set<Post> getPostsFromIDs(Set<Long> postsIDs) {
		Set<Post> tContainingPosts = new HashSet<Post>();
		for (Long postID : postsIDs) {
			Post tPost = this._postsIndex.get(postID);
			tContainingPosts.add(tPost);
		}
		return tContainingPosts;
	}


	/* (non-Javadoc)
	 * @see interfaces.SearchDataBase#getUserPosts(java.lang.String)
	 */
	public Set<Post> getUserPosts(String userName) {
		Set<Long> tPostsID = this._usersToPostsIndex.get(userName);
		return this.getPostsFromIDs(tPostsID);
	}




	/* (non-Javadoc)
	 * @see interfaces.SearchDataBase#getPostsByDate(java.util.Date, java.util.Date)
	 */
	public Set<Post> getPostsByDate(Date start, Date end) {
		Calendar tCurDate = new GregorianCalendar();
		tCurDate.setTime(start);
		Set<Long> tPostsID = new HashSet<Long>();
		while (!tCurDate.after(end)) {
			Set<Long> tPostsFromCurDate = this._datesToPostsIndex.get(tCurDate);
			tPostsID.addAll(tPostsFromCurDate);
			tCurDate.add(Calendar.DAY_OF_MONTH, 1);
		}
		return this.getPostsFromIDs(tPostsID);
	}


	public void removeUserPost(String userName, Post post) {
		Set<Long> tUserPosts = this._usersToPostsIndex.get(userName);
		tUserPosts.remove(post.getId());
	}



	public void removeWordReference(String word, Post post) {
		Set<Long> tWordsPosts = this._wordsToPostsIndex.get(word);
		tWordsPosts.remove(post.getId());
	}






}
